package com.sailorj.util;

import com.google.gson.Gson;
import com.sailorj.entity.SysLog;
import com.sailorj.entity.SysUser;
import com.sailorj.service.SysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
@Aspect
public class LogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
    @Autowired
    private SysLogService sysLogService;

    /**
     * @Description: 切入点定义，控制层下面的所有方法的所有值,排除自身log的方法
     * @Param: []
     * @return: void
     * @Author: huangshengjun
     * @Date: 2020/4/1 23:56
     */
    @Pointcut("execution(* com.sailorj.controller.*.*(..)) && !execution(* com.sailorj.controller.SysLogController.*(..))")
    public void logPointCut() {
    }

    /**
     * @Description: 前置通知，在目标方法执行之前执行
     * 通过 JoinPoint参数可以获取目标方法的方法名、修饰符等信息
     * @Param: [jp]
     * @return: void
     * @Author: huangshengjun
     * @Date: 2020/4/1 23:56
     */
    @Before(value = "logPointCut()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        logger.info(" -- > " + name + " 方法开始执行");
    }


    /**
     * @Description:后置通知，在目标方法执行之后执行
     * @Param: [jp]
     * @return: void
     * @Author: huangshengjun
     * @Date: 2020/4/1 23:55
     */
    @After(value = "logPointCut()")
    public void after(JoinPoint jp){
        String name = jp.getSignature().getName();
        logger.info(" -- > " + name + "方法执行结束");
    }

    /**
     * @Description: 返回通知，获取目标方法的返回值 ，returning 参数是指返回值的变量名，对应方法的参数
     * @Param: [jp, result]
     * @return: void
     * @Author: huangshengjun
     * @Date: 2020/4/1 23:59
     */
    @AfterReturning(value = "logPointCut()", returning ="result")
    public void afterReturning(JoinPoint jp ,Object result){
        String name = jp.getSignature().getName();
        //转化成json对象
        //JSONObject jsonResult = JSONObject.fromObject(name);
        //输出
        String list = GsonUtil.GsonString(result);
        logger.info(" -- > " + name + "方法返回值为：==Gson==" + list);
    }


    /**
     * @Description: 异常通知
     * @Param: [jp, e]
     * @return: void
     * @Author: huangshengjun
     * @Date: 2020/4/2 0:01
     */
    @AfterThrowing(value = "logPointCut()", throwing ="e")
    public void afterThrowing(JoinPoint jp ,Exception e){
        String name = jp.getSignature().getName();
        logger.info(" -- > " + name + "方法抛异常了，异常是：" + e.getMessage());
    }

    /**
     * @Description: 环绕通知 是所有通知
     * 里功能最为强大的通知，可以实现前直通知、后直通知、异常通知以及返回通知的功能
     * @Param: [pjp]
     * @return: java.lang.Object
     * @Author: huangshengjun
     * @Date: 2020/4/2 0:01
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        long beginTime = System.currentTimeMillis();
        Object result = pjp.proceed();
        long time = System.currentTimeMillis() - beginTime;
        try {
            saveLog(pjp, time);
        } catch (Exception e) {
        }
        return result;
//        return pjp.proceed();
    }


    private void saveLog(ProceedingJoinPoint joinPoint, long time) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLog sysLog = new SysLog();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        //读取session中的用户 以及IP地址
        SysUser user = (SysUser) session.getAttribute("user");
        String ip = IpUtil.getIpAddr(request);
        sysLog.setIp(ip);

//        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sysLog.setCreaterTime(new Date());
        SysLoging sysLoging = method.getAnnotation(SysLoging.class);
        if (sysLoging != null) {
            //控制层注解上的描述
            sysLog.setRemark(sysLoging.value());
        }
        // 请求的类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setClassesName(className);
        sysLog.setMethodsName(methodName);
        // 请求的参数
        Object[] args = joinPoint.getArgs();
        try {
            List<String> list = new ArrayList<String>();
            for (Object o : args) {
                list.add(new Gson().toJson(o));
            }
            sysLog.setParamses(list.toString());
        } catch (Exception e) {
        }
        logger.info(" -- >  操作日志>" + GsonUtil.GsonString(sysLog));
        sysLogService.addSysLog(sysLog);
    }

}